gitのcredential.helperを理解してCodeCommitの403エラーを回避してみた
はじめに
こんにちは、平野です。
先日下記のブログが投稿されたのとほぼ同じタイミングで私も同じ状態に陥っていたため、対応策を探していました。
対応策がいろいろあるようですが、credential.helperの動作を調べたところ、 ある程度納得できる対処できるができました。
問題の状況
CodeCommitにクロスアカウントでアクセスする際には CodeCommitのマニュアル に書かれている通り設定すればよく、結果として、globalなり、localなりに
[credential] helper=!aws codecommit credential-helper --profile MyCrossAccountAccessProfile $@
が設定されているはずです。
しかし、MacのgitでCodeCommitを使用している場合、 初回はうまくいくのですが、それからしばらく時間が経つと認証を通らなくなってしまいます。
対処法
まず先に対処法を書きます。 root権限が必要な部分を触るのでお気をつけ下さい。
/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig
を編集します。
[credential] helper = osxkeychain
を以下のように変更します。
[credential] helper = osxkeychain_wrapper
次にgit-credential-osxkeychain_wrapper
を作成します。
#!/bin/bash if grep -q ' codecommit credential-helper ' ${GIT_DIR}/config; then exit fi readonly OSXKEYCHAIN_SCRIPT="/Applications/Xcode.app/Contents/Developer/usr/libexec/git-core/git-credential-osxkeychain" eval "${OSXKEYCHAIN_SCRIPT} \"$@\""
このファイルを/Applications/Xcode.app/Contents/Developer/usr/libexec/git-core/git-credential-osxkeychain_wrapper
として保存します。
(フルパスは人によって異なるかもしれないので、後の解説を参照)
2019/11/11追記 上記のファイルには実行権限が必要なので、以下のように実行権限をつけます。
sudo chmod +x git-credential-osxkeychain_wrapper
追記終わり
以上で完了です。
問題の整理
gitの設定について
gitの現在の設定はgit config -l
で確認できます。
CodeCommitの設定を行った状態では、以下のようになります。
$ git config -l credential.helper=osxkeychain credential.helper=!aws codecommit credential-helper --profile MyCrossAccountAccessProfile $@ (credential.helper以外は省略)
上記のように、同じ項目(ここではcredential.helper)が複数表示されることがあります。 これはgitの設定箇所が複数あり、ローカルな設定ほど下に書かれます。 gitはこの設定を上から順に見ていきますので、ここに表示される設定は後勝ちとなります。
credential.helperの場合
しかし、credential.helperに関しては、 Gitのマニュアル に、
サーバーの認証情報が必要になると Git はこれらを順番に検索をかけていき、ヒットした時点で検索を中断します。
と書かれている通り、上から評価して、 ヒットした時点で中断 されてしまいます。 なのでcredential.helperについては、上位で認証情報が得られた場合、下位のものは無視されてしまうようです。
CodeCommitのリポジトリにアクセスする際、初回はキーチェーンにそれに関連する情報がないので、
credential.helper=osxkeychain
の部分はスルーされ、
aws codecommit credential.helper
のコマンドが実行されます。
そして、そこで得られた認証情報がキーチェーンに登録されます。
その後しばらくはキーチェーンを参照することで正しい認証情報が得られるので、
aws codecommit credential.helper
コマンドを実行することなくリモートリポジトリに接続することができます。
しかし、CodeCommitの認証システムでは15分たつと新しい認証情報が必要になりますので、
それ以降はキーチェーンの情報では認証を通ることができません。
また、credential.helperは、認証を実際に通過できたかは関知しないので、
この状態ではキーチェーンは古い情報しか出さない上に、aws codecommit credential.helper
のコマンドも実行されなくなってしまいます。
解決方法の模索
誰がOSのキーチェーン使用を設定している?
最下位のcredential.helperがどこで設定されているかは以下のコマンドで参照できます。
git config --show-origin --get credential.helper
ローカルなどからcredential.helperの設定を外した状態で見てみると、
/Applications/Xcode.app/Contents/Developer/usr/share/git-core/gitconfig
というファイルで設定されていることがわかります。
中身は以下のようになっていました。
[credential] helper = osxkeychain
ここでcredential.helperとしてOSのキーチェーンを使用するように書かれています。
osxkeychainをラップする
gitの認証情報の保存に関する情報 を見ると、gitの認証情報の保持の仕方が解説されています。
マニュアルによると、osxkeychain
という記述があった場合、
保存されている認証情報を取得するためには
git-credential-osxkeychain get
というコマンドが実行されるようです。
またosxkeychain
という記述はgit-credential-
に後続する部分だけを省略して指定できる機能を使っているようです。
そしてこのファイルは
/Applications/Xcode.app/Contents/Developer/usr/libexec/git-core/git-credential-osxkeychain
という場所にありました。1
ということで、git-credential-osxkeychain
をラップしたプログラムを用意します。
CodeCommitかどうかを判別し、CodeCommitだった場合は何もせずに終了とし、
そうでない場合にはgit-credential-osxkeychain
へ移譲を行うようにします。
このラッパーが何もせずに終了した場合には、より下位のcredential.helperの評価に進みます。
CodeCommitかどうかの判別方法
git-credential-osxkeychain_wrapper
を実行するプロセスでは、GIT_DIR
という環境変数が設定されており、
それが現在のレポジトリの.git
ディレクトリをさすようになっています。
なので、そこから簡単にconfig
ファイルの場所を知ることができます。
あとはconfig
ファイル内でCodeCommitのcredential.helperを使用しているかを確認すればOKです。
Xcodeを更新した場合
2019/11/11追記 Xcodeを新しいバージョンに上げたとところ、 上記で設定したファイルが全てデフォルトの状態に戻っていたようでした。 再び同様に設定した所同じように動作することが確認できました。
やはり、公式的にはあまりオススメされないやり方ではあるかと思いますので、 その点はご留意頂きたいと思います。 追記終わり
まとめ
Macで、CodeCommitにhttpsで接続した場合、15分経つと接続ができなくなってしまう問題が生じます。 そこで、CodeCommitを使用した場合にはOSのキーチェーンを使用せず、 よりローカルな設定に任せる方法をご紹介しました。
credential.helperがグローバルな設定を先に評価してしまい、 ローカルな設定にたどり着けないという挙動はなかなか影響が大きく、 CodeCommit以外にも同様な問題に当たる可能性はあるかなと思います。 その際にも、上記の方法で回避が可能になるかと思いますので、お試し頂ければと思います。
以上、誰かの参考になれば幸いです。
-
これは単純に
find
でコマンドで探しました。 ↩